package cuatroenraya.jugadores;

import cuatroenraya.Jugador;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class JugadorAlumnoG21 extends Jugador implements Comparable {


    private int matriz[][];
    private int ganador = 0;
    private int nivel = 0;
    private int ultimoJugador;
    public int peso = 0;
    private List<JugadorAlumnoG21> childs;
    public static int niveles;
    public static int childrens;
    public static int cantJuegos;
    private static final int CONTRINCANTE = 2;


    public JugadorAlumnoG21() {
        cantJuegos++;
    }


    public JugadorAlumnoG21(int x, int y, int ultimoJugador) {
        cantJuegos++;
        this.matriz = new int[x][y];
        this.ultimoJugador = (ultimoJugador == 1) ? 2 : 1;
        //generarChilds();
    }

    public JugadorAlumnoG21(int[][] matriz, int ultimoJugador) {
        cantJuegos++;
        this.matriz = matriz;
        this.ultimoJugador = (ultimoJugador == 1) ? 2 : 1;
        //generarChilds();
    }

    public List<JugadorAlumnoG21> getChildsWinners() {

        List<JugadorAlumnoG21> wins = new ArrayList<JugadorAlumnoG21>();
        List<JugadorAlumnoG21> childs = this.getChilds();

        for (int i = 0; i < childs.size(); i++) {
            if (childs.get(i).getGanador() != 0) {
                wins.add(childs.get(i));
            }
        }
        return wins;

    }

    public int minPos(int[] vector) {
        int band = 0;
        int min = 0;

        for (int i = 0; i < vector.length; i++) {
            if (vector[i] < min || band == 0) {
                min = vector[i];
                band = 1;
            }
        }
        return min;
    }

    public int maxPos(int[] vector) {
        int band = 0;
        int max = 0;

        for (int i = 0; i < vector.length; i++) {
            if (vector[i] > max || band == 0) {
                max = vector[i];

                band = 1;
            }
        }
        return max;
    }

    private int[] near(int[][] matriz) {

        int i = 0;
        int j = 0;
        int prob[] = new int[6];

        for (i = 0; i < matriz.length; i++) {
            for (j = 0; j < matriz.length; j++) {
                if (matriz[i][j] == CONTRINCANTE) {
                    break;
                }
            }
        }

        return prob;

    }

    private void primeroEnAnchura(List abierta, List cerrada, List juegos) {
        //List abierta = new ArrayList();
        //  System.out.println("abierta "+ abierta.size());
        // System.out.println("cerrada "+ cerrada.size());
        // System.out.println("juegos "+ juegos.size());


        if (abierta.size() > 0) {
            JugadorAlumnoG21 m = (JugadorAlumnoG21)abierta.get(0);
            //System.out.println("abierta antes de borrar " + abierta.size());
            abierta.remove(m);
            //System.out.println("abierta despues de borrar" + abierta.size());
            cerrada.add(m);
            abierta.addAll(m.getChilds());
            for (int i = 0; i < abierta.size(); i++) {
                int[] res = m.getJuego(((JugadorAlumnoG21)abierta.get(i)).getMatriz());
                if (res[0] != 0) {
                    //System.out.println(imprimirMatrizHtml(((JugadorAlumnoG21)abierta.get(i)).getMatriz()));
                    juegos.add(abierta.get(i));
                }
            }
            //if(juegos.size() < (matriz.length*matriz[0].length)){
            if (juegos.size() < 1) {
                primeroEnAnchura(abierta, cerrada, juegos);
            }
        }
    }

    private void primeroElMejor(List abierta, List cerrada, List juegos) {
        //List abierta = new ArrayList();
        //  System.out.println("abierta "+ abierta.size());
        // System.out.println("cerrada "+ cerrada.size());
        // System.out.println("juegos "+ juegos.size());


        if (abierta.size() > 0) {
            JugadorAlumnoG21 m = (JugadorAlumnoG21)abierta.get(0);
            // System.out.println("abierta antes de borrar " + abierta.size());
            abierta.remove(m);
            System.out.println("abierta despues de borrar" + abierta.size());
            cerrada.add(m);
            abierta.addAll(m.getChilds());
            Collections.sort(abierta);
            for (int i = 0; i < abierta.size(); i++) {
                JugadorAlumnoG21 n = (JugadorAlumnoG21)abierta.get(i);
                //System.out.println(n.getPeso());
                int res[] = m.getJuego(m.getMatriz());
                if (res[0] != 0) {
                   // System.out.println(imprimirMatrizHtml(((JugadorAlumnoG21)abierta.get(i)).getMatriz()));
                    juegos.add(abierta.get(i));
                    break;
                }
            }
            //if(juegos.size() < (matriz.length*matriz[0].length)){
            if (juegos.size() < 1) {
                primeroElMejor(abierta, cerrada, juegos);
            }
        }
    }

    private void aAsterisco(List abierta, List cerrada, List juegos) {
        //List abierta = new ArrayList();
        //  System.out.println("abierta "+ abierta.size());
        // System.out.println("cerrada "+ cerrada.size());
        // System.out.println("juegos "+ juegos.size());


        if (abierta.size() > 0 && cerrada.size() < 64) {
            JugadorAlumnoG21 m = (JugadorAlumnoG21)abierta.get(0);
            // System.out.println("abierta antes de borrar " + abierta.size());
            abierta.remove(m);
           // System.out.println("abierta despues de borrar" + abierta.size());
            cerrada.add(m);
           // System.out.println("cerrada despues de borrar" + cerrada.size());
            if(m.getNivel() < 3){
              abierta.addAll(m.getChilds());
            }
            ComparadorAAsterisco comp = new ComparadorAAsterisco();
            Collections.sort(abierta, comp);
            for (int i = 0; i < abierta.size(); i++) {
                JugadorAlumnoG21 n = (JugadorAlumnoG21)abierta.get(i);
                //System.out.println(n.getPeso());
                int res[] = m.getJuego(n.getMatriz());
                if (res[0] != 0) {
                    //System.out.println(imprimirMatrizHtml(((JugadorAlumnoG21)abierta.get(i)).getMatriz()));
                    juegos.add(abierta.get(i));

                }
            }
            //if(juegos.size() < (matriz.length*matriz[0].length)){
            if (juegos.size() < 1 ) {
             //   System.out.println("Juegos " + juegos.size());
                aAsterisco(abierta, cerrada, juegos);
            }
        }
    }

    public int[] jugar(int[][] tablero) {

        int jugadas = 0;

        for (int i = 0; i < tablero.length; i++) {
            for (int j = 0; j < tablero[0].length; j++) {
                if (tablero[i][j] != 0) {
                    jugadas++;
                }
            }
        }


        JugadorAlumnoG21 JugadorAlumnoG21 = new JugadorAlumnoG21(tablero, 1);
        List<JugadorAlumnoG21> winners = JugadorAlumnoG21.getChildsWinners();
        int resp[];
        int ataque[] = new int[2];
        int defensa[] = new int[2];
        if (winners.size() != 0) {
            for (int i = 0; i < winners.size(); i++) {

                JugadorAlumnoG21 juego1 = winners.get(i);
                resp = juego1.compararMatCoor(tablero);
                if (resp[2] == 1) {
                    ataque[0] = resp[0];
                    ataque[1] = resp[1];
                    return ataque;
                } else if (resp[2] == 2) {
                    defensa[0] = resp[0];
                    defensa[1] = resp[1];
                }
            }
            return defensa;

        } else {
            List abierta = JugadorAlumnoG21.getChilds();
            List cerrada = new ArrayList();
            List juegos = new ArrayList();
            List resultado= juegos;
            if (jugadas > 1) {
                aAsterisco(abierta, cerrada, juegos);
            }
            if(juegos.size() ==0){
                resultado= cerrada;
            }
            
            //Collections.sort(juegos);
            //   System.out.println("abierta "+ abierta.size());
            //   System.out.println("cerrada "+ abierta.size());
               System.out.println("resultado "+ resultado.size());
               
             

            if (resultado.size() != 0) {

                Collections.sort(resultado, new ComparadorAAsterisco());
                for (int i = 0; i < resultado.size(); i++) {
                    JugadorAlumnoG21 win = ((JugadorAlumnoG21)resultado.get(i));
                    System.out.println("ganador" + win.getGanador() + 
                                       " Nivel" + win.getNivel()+
                                       "peso" + win.getPeso());
                    System.out.println(imprimirMatrizHtml(win.getMatriz()));


                }
                JugadorAlumnoG21 win = ((JugadorAlumnoG21)resultado.get(0));
                
                resp = new int[2];
                int dif[][] = compararMat(win.getMatriz(), tablero);
                for (int i = 0; i < dif.length; i++) {
                    for (int j = 0; j < dif[0].length; j++) {
                        if (win.getGanador() == 1 && 
                            dif[i][j] == 1) { //TODO CAMBIAR LA OPCION DEL CONTRICANTE
                            resp[0] = i;
                            resp[1] = j;
                            return resp;
                            
                        } else if (win.getGanador() == 2 && 
                                   dif[i][j] == 2) { //TODO CAMBIAR LA OPCION DEL CONTRICANTE
                            resp[0] = i;
                            resp[1] = j;
                            return resp;
                        } else {
                            resp = win.compararMatCoor(tablero);
                            return resp;
                        }
                    }
                }


                return resp;

            } else {
                while (true) {
                    resp = new int[2];
                    resp[0] = (int)(tablero.length * (Math.random()));
                    resp[1] = (int)(tablero[0].length * (Math.random()));
                    System.out.println("POR RANDOM");
                    if (tablero[resp[0]][resp[1]] == 0)
                        return resp;
                }
            }

        }

    }


    public List generarChilds() {

        List<JugadorAlumnoG21> childs = new ArrayList<JugadorAlumnoG21>();
        int[][] matriz = this.getMatriz();
        int ultimo = (this.getUltimoJugador() == 1) ? 2 : 1;
        if (this.getGanador() == 0) {
            for (int i = 0; i < matriz.length; i++) {
                for (int j = 0; j < matriz[0].length; j++) {

                    if (matriz[i][j] == 0) {
                        int copia[][] = copiarMatriz(matriz);
                        copia[i][j] = ultimo;
                        JugadorAlumnoG21 child = new JugadorAlumnoG21();
                        child.setMatriz(copia);
                        child.setUltimoJugador(ultimo);
                        child.setNivel(nivel + 1);
                        //System.out.println(child.getNivel());
                        if (child.getNivel() > childrens) {
                            childrens = child.getNivel();
                        }
                        int[] ganador = getJuego(copia);
                        child.setGanador(ganador[0]);
                        child.setPeso(ganador[1]);
                        //      System.out.println(imprimirMatrizHtml(copia)+ "<br>Nivel "+this.getNivel() );
                        childs.add(child);
                    }
                }
            }

        }

        //  System.out.println("nivel :"+nivel+ " childs"+ childs.size() );
        return childs;

    }

    private int[][] copiarMatriz(int[][] matriz) {
        int[][] copia = new int[matriz.length][matriz[0].length];
        for (int i = 0; i < matriz.length; i++) {
            for (int j = 0; j < matriz[0].length; j++) {
                copia[i][j] = matriz[i][j];

            }
        }
        return copia;

    }

    private int[][] compararMat(int[][] matriz, int[][] matriz1) {
        int[][] copia = new int[matriz.length][matriz[0].length];
        for (int i = 0; i < matriz.length; i++) {
            for (int j = 0; j < matriz[0].length; j++) {
                if (matriz[i][j] != matriz1[i][j] && matriz1[i][j] == 0) {
                    copia[i][j] = matriz[i][j];
                }
            }
        }
        return copia;

    }

    private int[] compararMatCoor(int[][] matriz1) {
       
        //System.out.print("\n entra a prim");
        int[] coord = new int[3];
        boolean prim = true; 
        int g1= this.getJuego(matriz1)[1];
        for (int i = 0; i < matriz.length; i++) {
            for (int j = 0; j < matriz[0].length; j++) {
                if (matriz[i][j] != matriz1[i][j] && matriz1[i][j] == 0) {
                    int [][] copia =copiarMatriz(matriz1);
                        if (g1 >= this.getJuego(copia)[1] || prim);{
                            prim=false;
                            coord[0] = i;
                            coord[1] = j;
                            coord[2] = matriz[i][j];
                            
                         }
                }
            }
        }
       
        return coord;

    }

    public int[] getJuego(int[][] matriz) {

        int[] JugadorAlumnoG21 = getJuegoDiagonal(matriz);
        if (JugadorAlumnoG21[0] != 0)
            return JugadorAlumnoG21;

        JugadorAlumnoG21 = getJuegoCruz(matriz);
        if (JugadorAlumnoG21[0] != 0)
            return JugadorAlumnoG21;

        return JugadorAlumnoG21;

    }


    public int diagonales() {

        int val = 1;
        int ancho = 7;
        int alto = 6;
        int countOpcion1 = 0;
        int countOpcion2 = 0;
        int aprox1 = 0;
        int aprox2 = 0;
        matriz = new int[ancho][alto];

        /*
        for (int jP = alto - 4; jP >= 0; jP--) {
            for (int i = 0, j = jP; i < ancho && j < alto; i++, j++) {
                matriz[i][j] = val++;

            }

        }
        for (int iP = 1; iP < ancho-3; iP++) {
            for (int j = 0, i = iP; i < ancho && j < alto; i++, j++) {
                matriz[i][j] = val++;

            }

        }
       */

        val = 1;
        // System.out.println(imprimirMatrizHtml(matriz));
        for (int jP = alto - 4; jP >= 0; jP--) {
            for (int i = alto - 1, j = jP; i >= 0 && j < alto; i--, j++) {

                matriz[i][j] = val++;

            }

        }

        for (int iP = ancho - 2; iP >= 3; iP--) {
            for (int j = 0, i = iP; i >= 0 && j < alto - 1; i--, j++) {
                matriz[i][j] = val++;

            }

        }
        //System.out.println(imprimirMatrizHtml(matriz));

        return 0;
    }

    public int[] getJuegoDiagonal(int[][] matriz) {

        int val = 4;
        int ancho = matriz.length;
        int alto = matriz[0].length;
        int countOpcion1 = 0;
        int countOpcion2 = 0;
        int aproxAux = 0;
        int aproxRes = 0;
        int res[] = new int[2];
        int[][] matriz1=new int[matriz.length][matriz[0].length]; 
        int newVal=1;



        for (int jP = alto - 4; jP >= 0; jP--) {
            for (int i = 0, j = jP; i < ancho  && j < alto; i++, j++) {
                matriz1[i][j]=newVal++;
                if (matriz[i][j] == 1) {
                    if (++countOpcion1 == val) {
                        res[0] = 1;
                        res[1] = aproxAux;
                        return res;
                    }

                    if (aproxAux < countOpcion1) {
                        aproxAux = countOpcion1;
                    }
                    countOpcion2 = 0;

                } else if (matriz[i][j] == 2) {
                    if (++countOpcion2 == val) {
                        res[0] = 2;
                        res[1] = aproxAux;
                        return res;
                    }

                    if (aproxAux < countOpcion2) {
                        aproxAux = countOpcion2;
                    }

                    countOpcion1 = 0;
                } else {
                    countOpcion1 = countOpcion2 = 0;
                }
            }
            countOpcion1 = countOpcion2 = 0;
        }
        
       
        //System.out.println(imprimirMatrizHtml(matriz1));
        
        newVal=1;
        matriz1=new int[8][8]; 
        
         for (int iP = 1; iP < ancho-3; iP++) {
             for (int j = 0 , i = iP; j < alto  && i< ancho; j++,i++) {
            
          matriz1[i][j]=newVal++;
                if (matriz[i][j] == 1) {
                    if (++countOpcion1 == val) {
                        res[0] = 1;
                        res[1] = aproxAux;
                        return res;
                    }

                    if (aproxAux < countOpcion1) {
                        aproxAux = countOpcion1;
                    }
                    countOpcion2 = 0;
                } else if (matriz[i][j] == 2) {
                    if (++countOpcion2 == val) {
                        res[0] = 2;
                        res[1] = aproxAux;
                        return res;
                    }

                    if (aproxAux < countOpcion2) {
                        aproxAux = countOpcion2;
                    }
                    countOpcion1 = 0;
                } else {
                    countOpcion1 = countOpcion2 = 0;
                }
            }
            countOpcion1 = countOpcion2 = 0;
        }
        newVal=1;
        
      //  System.out.println(imprimirMatrizHtml(matriz1));
        matriz1=new int[matriz.length][matriz[0].length]; 
        
        for (int jP = alto - 4; jP >= 0; jP--) {
            for (int i = alto-1 , j = jP; i >= 0 && j < alto; i--, j++) {
                matriz1[i][j]=newVal++;
                if (matriz[i][j] == 1) {
                    if (++countOpcion1 == val) {
                        res[0] = 1;
                        res[1] = aproxAux;
                        return res;
                    }

                    if (aproxAux < countOpcion1) {
                        aproxAux = countOpcion1;
                    }
                    countOpcion2 = 0;

                } else if (matriz[i][j] == 2) {
                    if (++countOpcion2 == val) {
                        res[0] = 2;
                        res[1] = aproxAux;
                        return res;
                    }

                    if (aproxAux < countOpcion2) {
                        aproxAux = countOpcion2;
                    }
                    countOpcion1 = 0;
                } else {
                    countOpcion1 = countOpcion2 = 0;
                }
            }
            countOpcion1 = countOpcion2 = 0;
        }
        newVal=0;
       
      //  System.out.println(imprimirMatrizHtml(matriz1));
        matriz1=new int[matriz.length][matriz[0].length]; 
        for (int iP = ancho - 1; iP >= 3; iP--) {
            for (int j = 0, i = iP; i >= 0 && j < alto ; i--, j++) {
                matriz1[i][j]=newVal++;
                if (matriz[i][j] == 1) {
                    if (++countOpcion1 == val) {
                        res[0] = 1;
                        res[1] = aproxAux;
                        return res;
                    }

                    if (aproxAux < countOpcion1) {
                        aproxAux = countOpcion1;
                    }
                    countOpcion2 = 0;
                } else if (matriz[i][j] == 2) {
                    if (++countOpcion2 == val) {
                        res[0] = 2;
                        res[1] = aproxAux;
                        return res;
                    }

                    if (aproxAux < countOpcion2) {
                        aproxAux = countOpcion2;
                    }
                    countOpcion1 = 0;
                } else {
                    countOpcion1 = countOpcion2 = 0;
                }
            }
            countOpcion1 = countOpcion2 = 0;
        }
        newVal=0;
      //  System.out.println(imprimirMatrizHtml(matriz1));

        res[1] = aproxAux;
        return res;
    }

    public int[] getJuegoCruz(int[][] matriz) {

        int ancho = matriz.length;
        int alto = matriz[0].length;
        int[][] matriz1=new int[matriz.length][matriz[0].length]; 
        int newVal=0;

        int val = 4;
        int countOpcion1 = 0;
        int countOpcion2 = 0;
        int res[] = new int[2];
        int aproxAux = 0;
        for (int j = 0; j < alto; j++) {
            for (int i = 0; i < ancho; i++) {
                matriz1[i][j]=newVal++;
                if (matriz[i][j] == 1) {
                    if (++countOpcion1 == val) {
                        res[0] = 1;
                        res[1] = aproxAux;
                        return res;
                    }
                    if (aproxAux < countOpcion1) {
                        aproxAux = countOpcion1;
                    }
                    countOpcion2 = 0;
                } else if (matriz[i][j] == 2) {
                    if (++countOpcion2 == val) {
                        res[0] = 2;
                        res[1] = aproxAux;
                        return res;
                    }
                    if (aproxAux < countOpcion2) {
                        aproxAux = countOpcion2;
                    }
                    countOpcion1 = 0;
                } else {
                    countOpcion1 = countOpcion2 = 0;
                }
            }
            countOpcion1 = countOpcion2 = 0;
        }
       // System.out.println(imprimirMatrizHtml(matriz1));
        newVal=0;
            for (int i = 0; i < ancho; i++) {
        for (int j = 0; j < alto; j++) {
            
                matriz1[i][j]=newVal++;
                if (matriz[i][j] == 1) {
                    if (++countOpcion1 == val) {
                        res[0] = 1;
                        res[1] = aproxAux;
                        return res;
                    }
                    if (aproxAux < countOpcion1) {
                        aproxAux = countOpcion1;
                    }
                    countOpcion2 = 0;
                } else if (matriz[i][j] == 2) {
                    if (++countOpcion2 == val) {
                        res[0] = 2;
                        res[1] = aproxAux;
                        return res;
                    }
                    if (aproxAux < countOpcion2) {
                        aproxAux = countOpcion2;
                    }
                    countOpcion1 = 0;
                } else {
                    countOpcion1 = countOpcion2 = 0;
                }
            }
            countOpcion1 = countOpcion2 = 0;
        }

        res[1] = aproxAux;
      //  System.out.println(imprimirMatrizHtml(matriz1)); 
        return res;
    }


    public static String imprimirMatrizHtml(int[][] matriz) {
        StringBuilder sb = new StringBuilder();
        
        sb.append("\n");
            for (int j = 0; j < matriz[0].length; j++) {
            sb.append("\n");
                 for (int i = 0; i <matriz.length; i++) {
                sb.append(" " + matriz[j][i] + " ");
            }
            sb.append("\n");
        }
        sb.append("\n");

        return sb.toString();
    }


    public void setMatriz(int[][] matriz) {
        this.matriz = matriz;
    }

    public int[][] getMatriz() {
        return matriz;
    }

    public void setGanador(int ganador) {
        this.ganador = ganador;
    }

    public int getGanador() {
        return ganador;
    }

    public void setNivel(int nivel) {
        this.nivel = nivel;
    }

    public int getNivel() {
        return nivel;
    }

    public void setChilds(List<JugadorAlumnoG21> childs) {
        this.childs = childs;
    }

    public List<JugadorAlumnoG21> getChilds() {
        this.childs = (childs == null) ? generarChilds() : childs;
        return childs;
    }

    public void setUltimoJugador(int ultimoJugador) {
        this.ultimoJugador = ultimoJugador;
    }

    public int getUltimoJugador() {
        return ultimoJugador;
    }


    public int compareTo(Object o) {

        if (((JugadorAlumnoG21)o).getPeso() > this.getPeso()) {
            return -1;
        }
        return 1;
    }


    public static void main(String[] args) {
        int[][] mat = new int[7][6];

        mat[2][0] = 1;
        mat[1][1] = 1;
        mat[2][2] = 1;
        mat[3][3] = 0;
        mat[4][4] = 0;
        mat[5][5] = 2;

        JugadorAlumnoG21 j = new JugadorAlumnoG21();
        //j.diagonales();
        System.out.println(j.getJuego(mat));
    }

    public void setPeso(int peso) {
        this.peso = peso;
    }

    public int getPeso() {
        return peso;
    }


    class ComparadorAAsterisco implements Comparator {

        public ComparadorAAsterisco() {

        }

        public int compare(Object o1, Object o2) {
            JugadorAlumnoG21 j1 = ((JugadorAlumnoG21)o1);
            JugadorAlumnoG21 j2 = ((JugadorAlumnoG21)o2);
            int p1 = (4 - j1.getPeso()) + j1.getNivel();
            int p2 = (4 - j2.getPeso()) + j2.getNivel();
            if (p1 > p2) {
                return 1;
            }
            return -1;
        }
    }

    class ComparadorNivel implements Comparator {

        public ComparadorNivel() {

        }

        public int compare(Object o1, Object o2) {
            JugadorAlumnoG21 j1 = ((JugadorAlumnoG21)o1);
            JugadorAlumnoG21 j2 = ((JugadorAlumnoG21)o2);
            int p1 = j1.getNivel();
            int p2 = j2.getNivel();
            if (p1 > p2) {
                return 1;
            }
            return -1;
        }
    }

}
